home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Classes / ObjDB / ObjDB.m < prev    next >
Encoding:
Text File  |  1992-07-30  |  49.0 KB  |  2,382 lines

  1. /*****
  2.  * ObjDB.c
  3.  *
  4.  *    Methods for a DataBase Object.
  5.  {
  6.  *****/
  7. #import "ObjDB.h"
  8. #import <objc/Storage.h>
  9. #import <streams/streams.h>
  10. #define    MAXLINE 80
  11. #define TRUE -1
  12. #define FALSE !TRUE
  13. #define ISNEW    FALSE
  14. #define EXISTS TRUE
  15. #define BIGNUM 0
  16. #define LASTISN 999999
  17.  
  18. @implementation ObjDB
  19.  
  20. - init: (char *)dbname data_use_fraction: (float)dFraction
  21. {
  22.     char    tmp_buffer[BUFFSIZE], name[BUFFSIZE], *space_locator;
  23.     int i, *isns;
  24.     [self setDescriptors];
  25.     myDFD = [[Storage alloc] initCount:0 elementSize:sizeof(FIELD)
  26.         description:field_desc];
  27.     storInfo = [[Storage alloc] initCount:0 elementSize:sizeof(DBINFO)
  28.         description:storage_desc];
  29.     isnTable = [[Storage alloc] initCount:0 elementSize:BUFFSIZE
  30.         description:isns_desc];
  31.     spaceTable =[[Storage alloc] initCount:0 elementSize:BUFFSIZE
  32.         description:space_table_desc];
  33.     buffers = [[Storage alloc] initCount:0 elementSize:sizeof(BUFFER)
  34.         description:buffer_desc];
  35.     cacheCalls=0;
  36.     cacheHits=0;
  37.     cacheWrites=0;
  38.     [self pushList:0];
  39.     myInfo = (DBINFO *)malloc(sizeof(DBINFO));
  40.     [storInfo addElement:(DBINFO *)myInfo];
  41.     strcpy(myInfo->dBaseName, dbname);
  42.     myInfo->data_file.blks = 1;
  43.     myInfo->data_file.rover = 0;
  44.     myInfo->max_isns = NUM_ISNS;
  45.     myInfo->max_keys = 0;
  46.     myInfo->num_keys = 0;
  47.     myInfo->last_isn = 0;
  48.     myInfo->data_frac = dFraction;
  49.     myInfo->buff_size = BUFFSIZE;
  50.     myInfo->version = VERSION;
  51.     myInfo->nbuf = 10;
  52.     
  53.     if (BUFFSIZE < 256)
  54.     {
  55.         printf("Error:  Buffer sizes less than 256 not allowed\n");
  56.         exit(0);
  57.     }
  58.     if (ISNRECSIZE <= 1)
  59.     {
  60.         printf("Error:  ISNRECSIZE <= 1\n");
  61.         exit(0);
  62.     }
  63.     if (ISNRECSIZE > ISNSIZE)
  64.     {
  65.         printf("Error:  ISNRECSIZE > ISNSIZE\n");
  66.         exit(0);
  67.     }
  68.     
  69. /*
  70.     i = BUFFSIZE;
  71.     printf("%02x",i);
  72.     put_num(tmp_buffer,&i);
  73.     printf("    Buffersize is %d\n",(int)get_num(tmp_buffer));
  74.  
  75. */
  76.     for (i=0; i<BUFFSIZE; i++)
  77.         tmp_buffer[i] = '\0';
  78.         
  79.     strcpy(name,myInfo->dBaseName);
  80.     strcat(name,".dat");
  81.     myInfo->data_file.ptr = fopen(name,"w");
  82.     for (i=0;i<myInfo->data_file.blks; i++)
  83.         fwrite(tmp_buffer, sizeof(char), BUFFSIZE, myInfo->data_file.ptr);
  84.     fclose(myInfo->data_file.ptr);
  85.     myInfo->data_file.ptr = fopen(name,"r+");
  86.     
  87.     isns = (int *)calloc(NUM_ISNS,ISNSIZE);
  88.     space_locator = (char *)calloc(BUFFSIZE,sizeof(char));
  89.     
  90.     for (i=0; i<NUM_ISNS; i++)
  91.             isns[i] = -1;
  92.     [isnTable addElement:(int *)isns];
  93.     
  94.     for (i=0; i<BUFFSIZE; i++)
  95.         space_locator[i] = '\0';
  96.     [spaceTable addElement:(char *)space_locator];
  97.         
  98.     buffer = (BUFFER *)malloc(sizeof(BUFFER));
  99.     buffer->block = -1;
  100.     buffer->count = 0;
  101.     buffer->update = FALSE;
  102.     
  103.     for (i=0;i<myInfo->nbuf;i++)
  104.         [buffers addElement:buffer];
  105.  
  106.     printf("Allocated %d buffers\n",[buffers count]);
  107.  
  108.     free(buffer);        
  109.     
  110.     
  111.     free(isns);
  112.     free(space_locator);
  113.     return self;
  114. }
  115.  
  116. - setDescriptors
  117. {
  118.  
  119.     sprintf(field_desc,"{i[3c]c[16c]c[12c]!!}");
  120.     sprintf(storage_desc,"{[100c]{!ii}iiiifiiiiiiiii}");
  121.     sprintf(isns_desc,"[%di]",NUM_ISNS);
  122.     sprintf(space_table_desc,"[%dc]",BUFFSIZE);
  123.     sprintf(buffer_desc,"{iii[%dc]}",BUFFSIZE);
  124.     sprintf(hash_desc,"{[24c]ii}");
  125.     return self;
  126. }
  127.  
  128. - close
  129. {
  130.     int i;
  131.     
  132.     for (i=0;i<10;i++)
  133.     {
  134.         buffer = [buffers elementAt:i];
  135.         if (buffer->update == TRUE)
  136.         {
  137. /*
  138.             printf("Writing block %d\n",buffer->block);
  139. */
  140.             writeRandom(buffer->data,myInfo->data_file.ptr,
  141.                     buffer->block,BUFFSIZE);
  142.         }
  143.     }
  144.     [storInfo replace:(DBINFO *)myInfo at:0];
  145.     fclose(myInfo->data_file.ptr);
  146.     return self;
  147. }
  148.  
  149. - free
  150. {
  151.     [super free];
  152.     return self;
  153. }
  154.  
  155. - awake
  156. {
  157.     char    name[BUFFSIZE];
  158.     int i;
  159.  
  160.     [super awake];
  161.     [self setDescriptors];
  162.     myInfo = [storInfo elementAt:0];
  163.     if ( myInfo->buff_size != BUFFSIZE )
  164.         {
  165.             printf("Error: Database %s created with buffersize = %d, not %d\n",
  166.                 myInfo->dBaseName,myInfo->buff_size,BUFFSIZE);
  167.             exit(0);
  168.         }
  169.     strcpy(name,myInfo->dBaseName);
  170.     strcat(name,".dat");
  171.     if ((myInfo->data_file.ptr = fopen(name,"r+")) == NULL)
  172.         {
  173.             printf("Error: No data file for DB %s\n",myInfo->dBaseName);
  174.             exit(0);
  175.         }
  176.     cacheCalls=0;
  177.     cacheHits=0;
  178.     cacheWrites=0;
  179.     [self pushList:0];
  180.     
  181.     buffers = [[Storage alloc] initCount:0 elementSize:sizeof(BUFFER) description:buffer_desc];
  182.         buffer = (BUFFER *)malloc(sizeof(BUFFER));
  183.         buffer->block = -1;
  184.         buffer->count = 0;
  185.         buffer->update = FALSE;
  186.         for (i=0;i<myInfo->nbuf;i++)
  187.             [buffers addElement:buffer];
  188. /*
  189.         printf("Allocated %d buffers\n",[buffers count]);
  190. */
  191.     free(buffer);
  192. /*
  193.     printf("Buffer data addresses are:\n");
  194.     for (i=0;i<myInfo->nbuf;i++)
  195.         {
  196.         buffer = [buffers elementAt:i];
  197.         printf("%d) %02x \n",i,&buffer->data);
  198.         }
  199. */
  200.     return self;
  201. }
  202.  
  203. - prtCacheStats
  204. {
  205.     printf("--------Cache Statistics--------\n");
  206.     printf("Calls : %d\n",cacheCalls);
  207.     printf("Writes: %d\n",cacheWrites);
  208.     printf("Hits:   %d\n\n",cacheHits);
  209.     return self;
  210. }
  211.  
  212. - (int)numberFlds
  213. {
  214.     return [myDFD count];
  215. }
  216.  
  217. - addFldDesc:(FIELD *)newFldDesc
  218.  
  219. {
  220.     int *isns, i;
  221.     
  222.     if (newFldDesc->keyed == 'K')    {
  223.     /*
  224.         Allocate key storage isn-lists, chain them
  225.         Allocate heads of hash tables for this key
  226.     */
  227.         newFldDesc->hash = [[Storage alloc] initCount:0 
  228.             elementSize:sizeof(KEY_VALUE) description:hash_desc];
  229.         newFldDesc->key_isns = [[Storage alloc] initCount:0 
  230.             elementSize:BUFFSIZE description:isns_desc];
  231.         
  232.          isns = (int *)calloc(NUM_ISNS,ISNSIZE);
  233.         /*    Initialize isns for keys    */
  234.         for (i=0; i<NUM_ISNS;i++)
  235.             isns[i] = 0;
  236.  
  237.          [newFldDesc->key_isns addElement:(int *)isns];
  238.         myInfo->num_keys++;
  239.         [myDFD addElement:(FIELD *)newFldDesc];
  240.         free(isns);
  241.         }
  242.     else
  243.         [myDFD addElement:(FIELD *)newFldDesc];
  244.     return self;
  245. }
  246.  
  247. - (FIELD *) getFldDesc:(int)theFldNum
  248. {
  249.     if ((theFldNum >= 0) && (theFldNum < [self numberFlds]))
  250.         return [myDFD elementAt:theFldNum];
  251.     else return NULL;
  252. }
  253.  
  254. - (int)getFldNumForAbbrev:(char *)fldAbbrev
  255. {
  256.     int i = [self numberFlds], j;
  257.     FIELD *myField;
  258.     
  259.     for (j = 0; j<i; j++)
  260.     {
  261.         myField = [self getFldDesc:j];
  262.         if ( !strcmp(myField->abbrev,fldAbbrev))
  263.             return j;
  264.     } 
  265.         return -1;
  266. }
  267.  
  268. - (int)numKeyedFlds
  269. {
  270.     return myInfo->num_keys;
  271. }
  272.  
  273. - loadDFD:(FILE *)dfd_file
  274. {
  275.     char        name[BUFFSIZE];
  276.     FIELD *myField = (FIELD *)malloc(sizeof(FIELD));
  277.     
  278.     strcpy(name,myInfo->dBaseName);
  279.     strcat(name,".dfd");
  280.     if((dfd_file = (FILE *)fopen(name,"r")) == NULL)
  281.     {
  282.         printf("Error: loadDFD...descriptor file %s not found\n",name);
  283.         return NULL;
  284.     }
  285.  
  286.     while(!feof(dfd_file))
  287.     {
  288.     fscanf(dfd_file,"%s %c %d %s %c %s\n",
  289.     myField->abbrev,&(myField->kind),&(myField->display_len)
  290.         ,myField->name,&(myField->keyed),myField->edit_mask);
  291.     [self addFldDesc:(FIELD *)myField];
  292.     }
  293.     free(myField);
  294.     close(dfd_file);
  295.     return self;
  296. }
  297.  
  298. - (char *)getBlk:(int) blkreq
  299. {
  300.     BUFFER *myBuffer;
  301.     
  302.     if (blkreq < myInfo->data_file.blks)
  303.         myBuffer = [self locBlk:blkreq];
  304.     else myBuffer = [self newBlk:blkreq];
  305.     return myBuffer->data;
  306.     
  307. }
  308.  
  309. - (BUFFER *)newBlk:(int) blkreq
  310. {
  311.     BUFFER *myBuffer;
  312.     int i;
  313.     char *space;
  314.     
  315.     myBuffer = [self locBlk:blkreq];
  316.     
  317.     for (i=0; i<BUFFSIZE; i++)
  318.         myBuffer->data[i] = '\0';
  319.         
  320.     if (blkreq/BUFFSIZE == [spaceTable count])
  321.     {
  322.         space = (char *)malloc(BUFFSIZE);
  323.         for (i=0; i<BUFFSIZE; i++)
  324.             space[i] = '\0';
  325.         [spaceTable addElement:(char *)space];
  326.         free(space);
  327.     }
  328.     
  329.     [self allocSpace:0 in:blkreq];
  330.     myInfo->data_file.blks++;
  331.     return myBuffer;
  332. }
  333.  
  334. - (BUFFER *)locBlk:(int) blkreq
  335. {
  336.     int i, j, k, lowcount;
  337.     BUFFER *myBuffer;
  338.     
  339.         cacheCalls++;
  340.     
  341.     j = [buffers count];
  342.     for (i=0; i<j; i++)
  343.     {
  344.             myBuffer = [buffers elementAt:i];
  345.             /*    Adjust useage counts */
  346.             myBuffer->count--;
  347.     }
  348.  
  349.     /*    See if block is already here */
  350.     for (i=0;i<j;i++)
  351.         {
  352.             myBuffer = [buffers elementAt:i];
  353.             if (myBuffer->block == blkreq)
  354.             {
  355.                 myBuffer->count++;
  356.                 cacheHits++;
  357.                 return myBuffer;
  358.             }
  359.         }
  360.     
  361.         myBuffer = [buffers elementAt:0];
  362.         k = 0;
  363.         lowcount = myBuffer->count;
  364.         
  365.         for (i=0;i<j;i++)
  366.         {
  367.             myBuffer = [buffers elementAt:i];
  368.             if (myBuffer->count < lowcount)
  369.             {
  370.                 lowcount = myBuffer->count;    
  371.                 k = i;
  372.             }
  373.         }
  374.         myBuffer = [buffers elementAt:k];
  375.         if (myBuffer->update == TRUE)
  376.             {
  377.             writeRandom(myBuffer->data,myInfo->data_file.ptr,
  378.                     myBuffer->block,BUFFSIZE);
  379. /*
  380.             printf("Block %d written out\n",myBuffer->block);
  381. */
  382.                 cacheWrites++;
  383.             }
  384.         if (blkreq < myInfo->data_file.blks)
  385.             readRandom(myBuffer->data,myInfo->data_file.ptr,
  386.                 blkreq,BUFFSIZE);
  387.         myBuffer->block = blkreq;
  388.         myBuffer->update = FALSE;
  389.         myBuffer->count = 0;
  390.  
  391.         return myBuffer;
  392. }
  393.  
  394. - write:(NXTypedStream *)typedStream
  395. {
  396.     int i, num_flds;
  397.     FIELD *myField;
  398.     
  399.     [super write:typedStream];
  400.     NXWriteObject(typedStream,myDFD);
  401.     NXWriteObject(typedStream,storInfo);
  402.     NXWriteObject(typedStream,isnTable);
  403.     NXWriteObject(typedStream,spaceTable);
  404.     
  405.     num_flds = [self numberFlds];
  406.     for (i=0; i<num_flds; i++)
  407.     {
  408.         myField = [self getFldDesc:i];
  409.         if (myField->keyed == 'K')
  410.         {
  411.             NXWriteObject(typedStream,myField->key_isns);
  412.             NXWriteObject(typedStream,myField->hash);
  413.         }
  414.     }
  415.     return self;
  416. }
  417.  
  418. - read:(NXTypedStream *)typedStream
  419. {
  420.     int i, num_flds;
  421.     FIELD *myField;
  422.     
  423.     [super read:typedStream];
  424.     myDFD = NXReadObject(typedStream);
  425.     storInfo = NXReadObject(typedStream);
  426.     isnTable = NXReadObject(typedStream);
  427.     spaceTable = NXReadObject(typedStream);
  428.     num_flds = [self numberFlds];
  429.     for (i=0; i<num_flds; i++)
  430.     {
  431.         myField = [self getFldDesc:i];
  432.         if (myField->keyed == 'K')
  433.         {
  434.             myField->key_isns = NXReadObject(typedStream);
  435.             myField->hash = NXReadObject(typedStream);
  436.         }
  437.     }
  438.     return self;
  439. }
  440.  
  441. - (int)numberIsns
  442. {
  443.     return myInfo->last_isn;
  444. }
  445.  
  446. int
  447. locisn(isn,buffer)
  448.     int    isn;
  449.     char buffer[];
  450. {
  451.     int    isnptr,isnlen,isnnum;
  452.         isnptr = 0;
  453.         while ((isnlen = 
  454.             nxtisn(&isnnum,&buffer[isnptr])) != 0) {
  455.         if (isnnum == isn) return(isnptr);
  456.         isnptr = isnptr + isnlen;
  457.         }
  458.         
  459.     return(-1);
  460. }
  461.  
  462. int
  463. nxtisn(isn,buffer)
  464.     int    *isn;
  465.     char buffer[];
  466. {
  467.     int    isnlen;
  468.     
  469.         isnlen =(int)get_num(&buffer[0]);
  470.         *isn = (int)get_num(&buffer[0+ISNRECSIZE]);
  471.     return(isnlen);
  472. }
  473.  
  474. int
  475. loc_eob(buffer)
  476.     char buffer[];
  477. {
  478.     int    rec_len, rec_ptr;
  479.     
  480.     rec_ptr = 0;
  481.     while((rec_len = (int)get_num(&buffer[rec_ptr])) != 0)
  482.         rec_ptr = rec_ptr + rec_len;
  483.     return(rec_ptr);
  484. }
  485.  
  486. int
  487. get_num(buffer)
  488.     char buffer[];
  489. {
  490.     int i, j, *k;
  491.     char tmp[ISNSIZE];
  492.     
  493.     if(ISNRECSIZE != ISNSIZE)
  494.         for(i=0;i<ISNSIZE;i++)
  495.             tmp[i] = '\0';
  496.         
  497.     for(i=0;i<ISNRECSIZE;i++)
  498.     {
  499.         j = ISNSIZE - ISNRECSIZE + i;
  500.         tmp[j] = buffer[i]; ;
  501.     }
  502.         k = &tmp[0];
  503.         return(*k);
  504. }
  505.  
  506. void
  507. put_num(buffer,val)
  508.     char    buffer[];
  509.     char    val[];
  510. {
  511.     int i, j, k, *l;
  512.     
  513.     for(i=0;i<ISNRECSIZE;i++)
  514.     {    
  515.         k = ISNSIZE - i - 1;
  516.         j = ISNRECSIZE - i - 1;
  517.         buffer[j] =val[k];
  518.     }
  519.     if(ISNRECSIZE < ISNSIZE)
  520.         for(i=ISNRECSIZE;i<ISNSIZE;i++)
  521.             if(val[ISNSIZE-i-1] != '\0')
  522.             {
  523.                 l = &val[0];
  524.                 printf("\nError: put_num...value %d would be truncated\n",*l);
  525.                 printf("         ISNRECSIZE is too small\n");
  526.                 exit(0);
  527.             }
  528.     return;    
  529. }
  530.  
  531. int
  532. pn_N_fld(recordptr)        /* Store a null field        */
  533.     char    recordptr[];
  534. {
  535.             recordptr[0] = 0x01;
  536.             recordptr[1] = '\0';
  537.             return(1);
  538. }
  539.  
  540. int
  541. pn_I_fld(j,recordptr)
  542.     char    recordptr[], j[];
  543. {
  544.     int i;
  545.     int val;
  546.         if( sizeof(i) == 2)
  547.                 recordptr[0] = 0x03;
  548.                 else recordptr[0] = 0x05;
  549.         val=0;
  550.         for (i=0; i < sizeof(i); i++)    {        
  551.             recordptr[i+1] = j[i];
  552.             val = val + j[i];
  553.             }
  554.         if( val == 0)    {
  555.             recordptr[0] = 0x01;
  556.             recordptr[1] = '\0';
  557.             return(1);
  558.         }
  559.             
  560.         /* signals last field */
  561.         recordptr[sizeof(i)+1] = '\0';
  562.         return(sizeof(i)+1);
  563. }
  564. int
  565. pn_L_fld(j,recordptr)
  566.     char    recordptr[], j[];
  567. {
  568.     int i;
  569.     long m;
  570.     int val;    
  571.             if( sizeof(m) == 2)
  572.                 recordptr[0] = 0x03;
  573.                 else recordptr[0] = 0x05;
  574.         val=0;
  575.         for (i=0; i < sizeof(m); i++)    {        
  576.             recordptr[i+1] = j[i];
  577.             val = val + j[i];
  578.             }
  579.         if( val == 0)    {
  580.             recordptr[0] = 0x01;
  581.             recordptr[1] = '\0';
  582.             return(1);
  583.         }
  584.             
  585.         recordptr[sizeof(m)+1] = '\0';
  586.         return(sizeof(m)+1);
  587. }
  588. int
  589. pn_A_fld(j,recordptr,recordlen)
  590.     char    recordptr[], j[];
  591.     int    recordlen;
  592. {
  593.     int len, i;
  594.     
  595. /*    This should trim off trailing blanks    */
  596.     if ( (len = strlen(j)) > 0 )    {
  597.         while(j[len] == ' ' )
  598.             if ( --len == 0 ) break;
  599.         }
  600.     /* get length of input string    */
  601.     len = min(++len,recordlen);
  602.     /* length will not include terminal 0    */
  603.     recordptr[0]=len+1;
  604.     for (i=0;i<len;i++)    recordptr[i+1] = j[i];
  605.     /* store (semi-)permanent end of record there */
  606.     recordptr[len+1] = '\0';
  607.     return(len+1);
  608. }
  609.  
  610. - (int)allocSpace: (int)space in:(int) block_allocated
  611. {
  612.     int    charno, i, comp_fact;
  613.     int block;
  614.     char *mybuffer;
  615.     
  616.     /*    byte which represents amount of space used
  617.         depends upon Buffer Size ( 0xFF = 256)
  618.     */
  619.         comp_fact = BUFFSIZE/256;
  620.     if (space > BUFFSIZE)
  621.     {
  622.         printf("Error: allocSpace...space %d not available\n",space);
  623.         exit(0);
  624.     }
  625.  
  626.         /* mark space used    */
  627.     
  628.         charno = block_allocated;
  629.         block = charno/BUFFSIZE;
  630.         charno = mod(charno,BUFFSIZE);
  631.         mybuffer = (char *)[spaceTable elementAt:block];
  632.         /* get space used in block    */
  633.         i = (mybuffer[charno] & 0xFF) * comp_fact ;
  634.         i = i + space ;        
  635.         if (i < 0 ) {
  636.             printf("Error: allocSpace...deallocation resulted in < 0\n");
  637.             exit(0);
  638.             }
  639.         if (i > BUFFSIZE) {
  640.             printf("Error: allocSpace...requested allocation not possible\n");
  641.             exit(0);
  642.             }
  643.         /* space is divided by comp_fact when stored */
  644.         i = ( i + (comp_fact - 1))/comp_fact;
  645.         mybuffer[charno]  =( i & 0xFF);
  646.     /* Return amount of buffer space used    */
  647.         myInfo->data_file.rover = block_allocated;
  648.         return((int)i*comp_fact);
  649.  
  650. }
  651.  
  652. - (int)findSpace: (int)space :(float)data_frac 
  653. {
  654.     int    rover, charno, i, comp_fact;
  655.     int old_rover, old_block, block;
  656.     char *mybuffer;
  657.  
  658.     /*    byte which represents amount of space used
  659.         depends upon Buffer Size ( 0xFF = 256)
  660.     */    
  661.     comp_fact = BUFFSIZE/256;
  662.     if (space > BUFFSIZE)
  663.     {
  664.         printf("Error: findSpace...space %d not available\n",space);
  665.         exit(0);
  666.     }
  667.     
  668.     /*    Find a block big enough to contain a record of length "space"    */
  669.     rover = myInfo->data_file.rover;
  670.     old_rover = rover;
  671.     old_block = -1;
  672.     i = 0;
  673.     
  674.     while(TRUE)    {
  675.         charno = rover;
  676.         block = charno/BUFFSIZE;
  677.         charno = mod(charno,BUFFSIZE);
  678.         if ( block != old_block )
  679.         {
  680.             mybuffer = (char *)[spaceTable elementAt:block];
  681.             old_block = block;
  682.         }
  683.         i = (mybuffer[charno] & 0xFF) ;
  684.     /* space is divided by comp_fact when stored in space avail list    */
  685.         i = i * comp_fact;
  686.         if (max(2*ISNSIZE+1,space) + i  <  BUFFSIZE * data_frac )    
  687.         return((int)rover); /* space + used space is adequate    */
  688.         rover = mod((myInfo->data_file.rover)++,myInfo->data_file.blks);
  689.         if (rover == old_rover)
  690.             return(-1L);
  691.         }
  692. }
  693.  
  694. - updBuf:(int)block
  695. {
  696.     BUFFER *myBuffer;
  697.  
  698.     myBuffer = [self locBlk:block];
  699.     myBuffer->update = TRUE;
  700.     return self;    
  701. }
  702.  
  703. - addKey:(char *)value isnNo:(int)isn field:(FIELD *)myField
  704. {
  705.     KEY_VALUE    *keys;
  706.     KEY_VALUE *fnd_keys;
  707.     int i, j, blk, next, old_blk, *isns;
  708.     
  709.     if ((i =[self findKey:value field:myField]) != -1)
  710.         {
  711.             fnd_keys = [myField->hash elementAt:i];
  712.             fnd_keys->count++;
  713.         if (isn < fnd_keys->first_isn)
  714.             {
  715.                 blk = isn/(NUM_ISNS);
  716.                 j = mod(isn,(NUM_ISNS));
  717.                 isns = [myField->key_isns elementAt:blk];
  718.                 isns[j] = fnd_keys->first_isn;
  719.                 fnd_keys->first_isn = isn;
  720.             }
  721.             else
  722.             {
  723.         next = fnd_keys->first_isn;
  724.         old_blk = -1;
  725.         while ( next < isn )
  726.         {
  727.             blk = next/(NUM_ISNS);
  728.             j = mod(next, (NUM_ISNS));
  729.             if (blk != old_blk)
  730.             {
  731.                 isns = [myField->key_isns elementAt:blk];
  732.                 old_blk = blk;
  733.             }
  734.             if((next = isns[j]) == 0)
  735.             {
  736.                 isns[j] = isn;
  737.                 return self;
  738.             }
  739.         }
  740.         isns[j] = isn;
  741.         blk = isn/(NUM_ISNS);
  742.         j = mod(isn,(NUM_ISNS));
  743.         isns = [myField->key_isns elementAt:blk];
  744.         isns[j] = next;
  745.         }
  746.             return self;
  747.         }
  748.     keys  = (KEY_VALUE *)malloc(sizeof(KEY_VALUE));
  749.     strcpy(keys->key_value,value);
  750.     keys->count = 1;
  751.     keys->first_isn = isn;
  752.     [myField->hash addElement:(KEY_VALUE *)keys];
  753.     free(keys);
  754.     return self;
  755. }
  756.  
  757. - (int)findKey:(char *)value field:(FIELD *)myField
  758. {
  759.     KEY_VALUE *keys;
  760.     int j, i;
  761.     
  762.     j = [myField->hash count];
  763.     for (i=0; i<j; i++)
  764.     {
  765.         keys = [myField->hash elementAt:i];
  766.         if (!strcmp(keys->key_value,value))
  767.             return i;
  768.     }
  769.     return -1;
  770. }
  771.  
  772. - deleteKey:(char *)value isnNo:(int)isn field:(FIELD *)myField
  773. {
  774.     KEY_VALUE *fnd_keys;
  775.     int i, j, *isns, blk, old_blk, prev, current, next;
  776.     
  777.     if ((i =[self findKey:value field:myField]) != -1)
  778.         {
  779.             fnd_keys = [myField->hash elementAt:i];
  780.             fnd_keys->count--;
  781.             if (fnd_keys->count == 0)
  782.             {
  783.             [myField->hash removeAt:i];
  784.             return self;
  785.             }
  786.         if (isn == fnd_keys->first_isn)
  787.         {
  788.             blk = fnd_keys->first_isn/(NUM_ISNS);
  789.             j = mod(fnd_keys->first_isn,(NUM_ISNS));
  790.             isns = [myField->key_isns elementAt:blk];
  791.             fnd_keys->first_isn = isns[j];
  792.             isns[j] = 0;
  793.             return self;
  794.         }
  795.         prev = fnd_keys->first_isn;
  796.         current = prev;
  797.         next = current;
  798.         old_blk = -1;
  799.         while (next <= isn)
  800.         {
  801.             blk = next/(NUM_ISNS);
  802.             j = mod(next,(NUM_ISNS));
  803.             if (blk != old_blk)
  804.             {
  805.                 isns = [myField->key_isns elementAt:blk];
  806.                 old_blk = blk;
  807.             }
  808.             prev = current;
  809.             current = next;
  810.             next = isns[j];
  811.             if (next == 0) break;
  812.         }
  813.         blk = prev/(NUM_ISNS);
  814.         j = mod(prev,(NUM_ISNS));
  815.         isns = [myField->key_isns elementAt:blk];
  816.         isns[j] = next;
  817.         blk = current/(NUM_ISNS);
  818.         j = mod(current,(NUM_ISNS));
  819.         isns = [myField->key_isns elementAt:blk];
  820.         isns[j] = 0;
  821.             return self;
  822.         }
  823.         printf("Warning: deleteKey...Key %s not found\n",value);
  824.         return self;
  825. }
  826.  
  827. - setKeyField:(char *)abbrev
  828. {
  829.     int i;
  830.     FIELD *myField;
  831.     int *isns;    
  832.     
  833.     if ((myField = 
  834.         [self getFldDesc:[self getFldNumForAbbrev:abbrev]]) == NULL)
  835.     {
  836.         printf("Field %s not in data base\n",abbrev);
  837.         return self;
  838.     }
  839.     
  840.     if (myField->keyed == 'K')
  841.     {
  842.         return self;
  843.     }
  844.     myField->hash = [[Storage alloc] initCount:0 elementSize:sizeof(KEY_VALUE) description:hash_desc];
  845.     myField->key_isns = [[Storage alloc] initCount:0 elementSize:BUFFSIZE description:isns_desc];
  846.     myField->keyed = 'K';
  847.     isns = (int *)calloc(NUM_ISNS, ISNSIZE);
  848.     /* initialize space for key isns */
  849.     for (i=0; i<NUM_ISNS; i++)
  850.         isns[i] = 0;
  851.     
  852.     for (i=0; i<myInfo->max_isns/(NUM_ISNS);i++)
  853.         [myField->key_isns addElement:(int *)isns];
  854.         
  855.     free(isns);
  856.     myInfo->num_keys++;
  857.     [self keyFld:abbrev];
  858.     return self;
  859. }
  860.  
  861. - unKeyField:(int)fldNum
  862. {
  863.     FIELD *myField;
  864.     
  865.     if ((myField = 
  866.         [self getFldDesc:fldNum]) == NULL)
  867.     {
  868.         printf("Field %d not in data base\n",fldNum);
  869.         return self;
  870.     }
  871.     
  872.     if (myField->keyed != 'K')
  873.         return self;
  874.     printf("Freeing keys for %s\n",myField->abbrev);
  875.     [myField->hash free];
  876.     [myField->key_isns free];
  877.     myField->keyed = 'N';
  878.     [myDFD replace:(FIELD *)myField at:fldNum];
  879.     myInfo->num_keys--;
  880.     [storInfo replace:(DBINFO *)myInfo at:0];
  881.     return self;
  882. }
  883.  
  884. - unKeyDB
  885. {
  886.     int i, nfields;
  887.     
  888.     if([self numKeyedFlds] == 0)
  889.     {
  890.         printf("Database not keyed\n");
  891.         return self;
  892.     }
  893.     nfields = [self numberFlds];
  894.     
  895.     for (i=0; i<nfields; i++)
  896.         [self unKeyField:i];
  897.     return self;
  898. }
  899.  
  900. - keyDB
  901. {
  902.     int i,j;
  903.     
  904.     if([self numKeyedFlds] > 0)
  905.     {
  906.         printf("Database already keyed\n");
  907.         return self;
  908.     }
  909.     j = [self numberIsns];
  910.     for(i=0; i<j; i++)
  911.     [self keyRecord:i];
  912.     return self;
  913. }
  914.  
  915. - prtKeyTableFor:(char *)abbrev
  916. {
  917.     FIELD *myField;
  918.     int i, k, *fnd_isns;
  919.     
  920.     if ((myField = 
  921.         [self getFldDesc:[self getFldNumForAbbrev:abbrev]]) == NULL)
  922.     {
  923.         printf("Field %s not in data base\n",abbrev);
  924.         return self;
  925.     }
  926.     
  927.     if (myField->keyed != 'K')
  928.     {
  929.         printf("Field Not keyed\n");
  930.         return self;
  931.     }
  932.  
  933.         fnd_isns = [myField->key_isns elementAt:0];
  934.         printf("Data for field %s \n",abbrev);
  935.         printf("----------Dump of first block----------\n");
  936.         for (k=0;k<10;k++)
  937.         {
  938.             printf("%d ) ",k*10);
  939.             for (i=0;i<10;i++)
  940.                 printf("%6d ",fnd_isns[i+k*10]);
  941.             printf("\n");
  942.         }
  943.     return self;
  944. }
  945.  
  946. - (int *)newList:(int)size
  947. {
  948.     int    *tmp;
  949.  
  950.     tmp = (int *)calloc(size+2,ISNSIZE);
  951.     *tmp = size;
  952.     tmp[size+1] = LASTISN;
  953.     return tmp;
  954. }
  955.  
  956. - (int *)pushList:(int)size
  957. {
  958.     if(Hold) free(Hold);
  959.     if(Last) Hold = Last;
  960.         else Hold = [self newList:0];
  961.     if(Isns) Last = Isns;
  962.         else Last = [self newList:0];
  963.     Isns = [self newList:size];
  964.     return Isns;
  965. }
  966.  
  967. - (int *)getIsnListforField:(char *)abbrev value:(char *)value 
  968. {
  969.     KEY_VALUE *keys;
  970.     int j, i, k, *fnd_isns, blk, old_blk, count, next;
  971.     FIELD *myField;
  972.     
  973.     if (!strcmp(abbrev,"*"))
  974.         if(!strcasecmp(value,"ALL"))
  975.         {
  976.             Isns = [self pushList:myInfo->last_isn];
  977.             k = 1;
  978.             for (i=0; i<myInfo->last_isn; i++)
  979.                 if([self getBlockwithIsn:i] != -1)
  980.                     Isns[k++] = i;
  981.             Isns[k] = LASTISN;
  982.             *Isns    = k - 1;
  983.             return Isns;
  984.         }
  985.  
  986.     if ((myField = 
  987.             [self getFldDesc:[self getFldNumForAbbrev:abbrev]]) == NULL)
  988.     {
  989.         printf("Field %s not in data base\n",abbrev);
  990.         return [self pushList:0];
  991.     }
  992.     
  993.     if (myField->keyed != 'K')
  994.     {
  995.         printf("Field Not keyed\n");
  996.         return [self pushList:0];
  997.     }
  998.  
  999.     if((j = [self findKey:value field:myField]) != -1)
  1000.     {
  1001.         keys = [myField->hash elementAt:j];
  1002.         count = keys->count;
  1003.         old_blk = -1;
  1004.         Isns = [self pushList:count];
  1005.         next = keys->first_isn;
  1006.         i = 0;
  1007.         while(1)
  1008.         {
  1009.             Isns[i+1] = next;
  1010.             i++;    /* i points to location just stored into */
  1011.             blk = next/(NUM_ISNS);
  1012.             k = mod(next,(NUM_ISNS));
  1013.             if (blk != old_blk)
  1014.             {
  1015.                 fnd_isns = [myField->key_isns elementAt:blk];
  1016.                 old_blk = blk;
  1017.             }
  1018.             next = fnd_isns[k];
  1019.             if (next == 0) break;
  1020.         }
  1021.         Isns[0] = count;
  1022.         Isns[i+1] = LASTISN;
  1023.         if(count != i)
  1024.             printf("Warning: getIsnListforField...count=%d, #found = %d\n",
  1025.                 count,i);
  1026.         return Isns;
  1027.     }
  1028.         return [self pushList:0];    
  1029. }
  1030.  
  1031. - (int *)getIsnListforField:(char *)abbrev value:(char *)value operator:(char *)oper;
  1032. {
  1033.     FIELD *myField;
  1034.     int    i, j, *new, *isns;
  1035.     char source[BUFFSIZE], field[256];
  1036.     
  1037.     if ((myField = 
  1038.             [self getFldDesc:[self getFldNumForAbbrev:abbrev]]) == NULL)
  1039.     {
  1040.         printf("Field %s not in data base\n",abbrev);
  1041.         return [self pushList:0];
  1042.     }
  1043.     
  1044.     switch(oper[0])    {
  1045.         case '=':
  1046.         case '^':
  1047.             break;
  1048.         default:
  1049.             printf("Operator %s not implemented for search\n",oper);
  1050.             return [self pushList:0];
  1051.     }
  1052.     
  1053.     Isns = [self pushList:*Isns];
  1054.     new = Isns;
  1055.     *new = 0;
  1056.     isns = Last;
  1057.     
  1058.     ++isns; ++new;
  1059.     
  1060.     strcpy(field,abbrev);
  1061.     strcat(field,",128,");
  1062.     
  1063.         switch(oper[0])    {
  1064.             case '=':            /* string equality    */    
  1065.     for (i=0;i<*Last;i++)    {
  1066.         [self getData:source atIsn:*isns describedBy: field];
  1067.                 if(!strcmp(source,value))    {
  1068.                     *new = *isns;
  1069.                     (*Isns)++;
  1070.                     new++;
  1071.                     }
  1072.                 isns++;
  1073.                 }
  1074.                 *new = LASTISN;
  1075.                 break;
  1076.             case '^':            /*    string contains */
  1077.     for (i=0;i<*Last;i++)    {
  1078.         [self getData:source atIsn:*isns describedBy: field];
  1079.         for (j=0;j<=strlen(source)-strlen(value);j++)    {
  1080.                 if(!strncmp(&source[j],value,strlen(value)))    {
  1081.                     *new = *isns;
  1082.                     (*Isns)++;
  1083.                     new++;
  1084.                     break;
  1085.                     }
  1086.                 }
  1087.         isns++;
  1088.         }
  1089.                 *new = LASTISN;
  1090.                 break;
  1091.             }
  1092.     return Isns;
  1093. }
  1094.  
  1095. - listKeysForField:(char *)abbrev
  1096. {
  1097.     KEY_VALUE *keys;
  1098.     int j, i;
  1099.     FIELD *myField;
  1100.     
  1101.     if ((myField = 
  1102.         [self getFldDesc:[self getFldNumForAbbrev:abbrev]]) == NULL)
  1103.     {
  1104.         printf("Field %s not in data base\n",abbrev);
  1105.         return self;
  1106.     }
  1107.     
  1108.     if (myField->keyed != 'K')
  1109.     {
  1110.         printf("Field Not keyed\n");
  1111.         return self;
  1112.     }
  1113.     j = [myField->hash count];
  1114.     for (i=0; i<j; i++)
  1115.     {
  1116.         keys = [myField->hash elementAt:i];
  1117.         printf("%d) %s - %d -> %d\n",
  1118.             i,keys->key_value,keys->count,keys->first_isn);
  1119.     }
  1120.     return self;
  1121. }
  1122.  
  1123. - (int) addData:(char *)source:(char *)descript
  1124. {
  1125.     int i, j, blk_alloc, use_isn;
  1126.     
  1127.     i = get_reclen(descript);
  1128.     if((blk_alloc = 
  1129.         [self findSpace:i :myInfo->data_frac]) == -1L)
  1130.     {
  1131.         [self getBlk:myInfo->data_file.blks];
  1132.         if((blk_alloc = 
  1133.             [self findSpace:i :myInfo->data_frac]) == -1L)
  1134.         {
  1135.             printf("Error: addData...Unable to allocate new space\n");
  1136.             exit(0);
  1137.         }
  1138. /*
  1139.         printf("Allocated new data block %d\n",blk_alloc);        
  1140. */
  1141.     }
  1142.     use_isn = [self geta_isn];
  1143.     j = [self addrec:blk_alloc:use_isn:source:descript];
  1144.     [self setIsn:use_isn ToBlock:blk_alloc];
  1145.     [self updBuf:blk_alloc];
  1146.     [self allocSpace:j in:blk_alloc];
  1147.     if([self numKeyedFlds] > 0)
  1148.         [self keyRecord:use_isn];
  1149.     return use_isn;
  1150. }
  1151.  
  1152. - (fld_index *)bldFldIndex:(char *)descript
  1153. {
  1154.     static char old_descript[BUFFSIZE] = "";
  1155.     static    int    *myfld;
  1156.     static    int    *myofset;
  1157.     static    int    l;
  1158.     int i,j,k, fldnum, fldlen;
  1159.     char    fld_name[3];
  1160.     static fld_index *myIndex;
  1161.     
  1162.     if (strcmp(old_descript,descript) != 0)    {
  1163.         strcpy(old_descript,descript);
  1164.     
  1165.     l = [self numberFlds];
  1166.     if(strcmp(old_descript,""))
  1167.     {
  1168.         myfld = (int *)calloc(l,sizeof(int));
  1169.         myofset = (int *)calloc(l,sizeof(int));
  1170.         myIndex = (fld_index *)malloc(sizeof(fld_index));
  1171.     }
  1172.     for (i=0; i<l;i++)    {
  1173.         myfld[i] = 0;
  1174.         myofset[i] = 0;
  1175.         }
  1176.     i = 0;
  1177.     j = 0;
  1178.     l = 0;
  1179.     k = 0;
  1180.     while(i < strlen(descript))    {
  1181.         j = get2(&descript[i],&fld_name,&fldlen);
  1182.         i = i + j;
  1183.         if ((fldnum = [self getFldNumForAbbrev:fld_name]) == -1 )
  1184.         {
  1185.          printf("Error: addrec...bad field %s in descript\n",fld_name);
  1186.          exit(0);
  1187.         }
  1188.         l = max(l,fldnum);
  1189.         myfld[fldnum] = fldlen;
  1190.         myofset[fldnum] = k;
  1191.         k = k + fldlen;
  1192.         }
  1193.         
  1194.     myIndex->fld = myfld;
  1195.     myIndex->ofset = myofset;
  1196.     myIndex->l = l + 1;
  1197.     }
  1198.     return myIndex;
  1199.  
  1200. }
  1201.  
  1202. - keyRecord:(int)isn
  1203. {
  1204.     char *mybuffer;
  1205.     char    num_str[BUFFSIZE];
  1206.     int j, k, nfields, blk;
  1207.     FIELD *myField;
  1208.     
  1209.     /* key data for record in isn */
  1210.     if ((blk = [self getBlockwithIsn:isn]) == -1)
  1211.         return NULL;    
  1212.     mybuffer = (char *)[self getBlk:blk];
  1213.     j = locisn(isn,&mybuffer[0]);
  1214.     nfields = [self numberFlds];
  1215.     for (k = 0; k < nfields; k++)    {
  1216.                 myField = [self getFldDesc:k];
  1217.         if ( myField->keyed == 'K' )
  1218.             switch (myField->kind)    {
  1219.                 case    'I':
  1220.                     if(gn_I_fld(num_str,k,&mybuffer[j]) != 0)
  1221.                     [self addKey:num_str isnNo:isn field:myField];
  1222.                     else [self addKey:"0" isnNo:isn field:myField];
  1223.                     break;
  1224.                 case    'L':
  1225.                     if(gn_L_fld(num_str,k,&mybuffer[j]) != 0)
  1226.                     [self addKey:num_str isnNo:isn field:myField];
  1227.                     else [self addKey:"0" isnNo:isn field:myField];
  1228.                     break;
  1229.                 case    'A':
  1230.                     if(gn_A_fld(num_str,k,BUFFSIZE,&mybuffer[j]) != 0)
  1231.                     [self addKey:num_str isnNo:isn field:myField];
  1232.                     else [self addKey:"" isnNo:isn field:myField];
  1233.                     break;
  1234.             }
  1235.             
  1236.     }
  1237.     return self;
  1238. }
  1239.  
  1240. - deKeyRecord:(int)isn
  1241. {
  1242.     char *mybuffer;
  1243.     char    num_str[BUFFSIZE];
  1244.     int j, k, nfields, blk;
  1245.     FIELD *myField;
  1246.     
  1247.     /* de-key data for record in isn */    
  1248.     if((blk = [self getBlockwithIsn:isn]) == -1)
  1249.         return NULL;
  1250.     mybuffer = (char *)[self getBlk:blk];
  1251.     j = locisn(isn,&mybuffer[0]);
  1252.     nfields = [self numberFlds];
  1253.     for (k = 0; k < nfields; k++)    {
  1254.                 myField = [self getFldDesc:k];
  1255.         if ( myField->keyed == 'K' )
  1256.             switch (myField->kind)    {
  1257.                 case    'I':
  1258.                     if(gn_I_fld(num_str,k,&mybuffer[j]) != 0)
  1259.                     [self deleteKey:num_str isnNo:isn field:myField];
  1260.                     else [self deleteKey:"0" isnNo:isn field:myField];
  1261.                     break;
  1262.                 case    'L':
  1263.                     if(gn_L_fld(num_str,k,&mybuffer[j]) != 0)
  1264.                     [self deleteKey:num_str isnNo:isn field:myField];
  1265.                     else [self deleteKey:"0" isnNo:isn field:myField];
  1266.                     break;
  1267.                 case    'A':
  1268.                     if(gn_A_fld(num_str,k,BUFFSIZE,&mybuffer[j]) != 0)
  1269.                     [self deleteKey:num_str isnNo:isn field:myField];
  1270.                     else [self deleteKey:"" isnNo:isn field:myField];
  1271.                     break;
  1272.             }
  1273.             
  1274.     }
  1275.     return self;
  1276. }
  1277.  
  1278. - keyFld:(char *)abbrev
  1279. {
  1280.     int    fldNum, i, j;
  1281.     
  1282.     if((fldNum = [self getFldNumForAbbrev:abbrev]) == -1)
  1283.     {
  1284.         printf("Error: keyFld...field %s not defined\n",abbrev);
  1285.         exit(0);
  1286.     }
  1287.     
  1288.     j = [self numberIsns];
  1289.     for (i=0; i<j; i++)
  1290.         [self keyFld:fldNum forIsnNum:i];
  1291.     return self;
  1292. }
  1293.  
  1294. - keyFld:(int)fldNum forIsnNum:(int)isn
  1295. {
  1296.     char *mybuffer;
  1297.     char    num_str[BUFFSIZE];
  1298.     int j, k, nfields, blk;
  1299.     FIELD *myField;
  1300.     
  1301.     /* key data for record in isn */
  1302.     if ((blk = [self getBlockwithIsn:isn]) == -1)
  1303.         return NULL;    
  1304.     mybuffer = (char *)[self getBlk:blk];
  1305.     j = locisn(isn,&mybuffer[0]);
  1306.     nfields = [self numberFlds];
  1307.     k = fldNum;
  1308.     myField = [self getFldDesc:k];
  1309.         if ( myField->keyed == 'K' )
  1310.             switch (myField->kind)    {
  1311.                 case    'I':
  1312.                     if(gn_I_fld(num_str,k,&mybuffer[j]) != 0)
  1313.                     [self addKey:num_str isnNo:isn field:myField];
  1314.                     else [self addKey:"0" isnNo:isn field:myField];
  1315.                     break;
  1316.                 case    'L':
  1317.                     if(gn_L_fld(num_str,k,&mybuffer[j]) != 0)
  1318.                     [self addKey:num_str isnNo:isn field:myField];
  1319.                     else [self addKey:"0" isnNo:isn field:myField];
  1320.                     break;
  1321.                 case    'A':
  1322.                     if(gn_A_fld(num_str,k,BUFFSIZE,&mybuffer[j]) != 0)
  1323.                     [self addKey:num_str isnNo:isn field:myField];
  1324.                     else [self addKey:"" isnNo:isn field:myField];
  1325.                     break;
  1326.             }
  1327.     return self;
  1328. }
  1329.  
  1330. - (int)addrec:(int)blkno:(int)isn:(char *)source:(char *)descript
  1331. {
  1332.     char    *mybuffer;
  1333.     FIELD    *myField;
  1334.     int    hold,i,j, k, l, zero;
  1335.     fld_index *myFlds;
  1336.     
  1337.     myFlds = [self bldFldIndex:descript];
  1338.     zero = 0;
  1339.     l = [self numberFlds];
  1340.     i = 0;
  1341.     mybuffer = (char *)[self getBlk:blkno];
  1342.     i = loc_eob(&mybuffer[0]);
  1343.     hold = i;
  1344.     put_num(&mybuffer[i+ISNRECSIZE],&isn);
  1345.     /* point past rec len and isn num    */
  1346.     i = i + ISNRECSIZE + ISNRECSIZE;
  1347.     /* reclen is stored in first ISNRECSIZE bytes */
  1348.     /* isn is stored in next ISNRECSIZE bytes    */
  1349.     j = i;
  1350.     
  1351.     for (k = 0; k <l; k++)    {
  1352.                 myField = [self getFldDesc:k];
  1353.                 if (myFlds->fld[k] == 0)
  1354.                 {
  1355.                     i = pn_N_fld(&mybuffer[j]);
  1356.                     j = i+j;
  1357.                 }
  1358.     else    switch (myField->kind)    {
  1359.             case    'I':
  1360.                 i = pn_I_fld(&source[myFlds->ofset[k]],&mybuffer[j]);
  1361.                     j=i+j;
  1362.                     break;
  1363.             case    'L':
  1364.                 i = pn_L_fld(&source[myFlds->ofset[k]],&mybuffer[j]);
  1365.                     j=i+j;
  1366.                     break;
  1367.             case    'A':
  1368.                 i = pn_A_fld(&source[myFlds->ofset[k]],
  1369.                         &mybuffer[j],myFlds->fld[k]);
  1370.                     j=i+j;
  1371.                     break;
  1372.             }
  1373.             
  1374.     }
  1375.     /* store record len    */
  1376.     k = j - hold;
  1377.     put_num(&mybuffer[hold+0],&k);    
  1378.     /* return record len    */
  1379.     return(k);
  1380. }
  1381.  
  1382. - getData:(char *)source atIsn:(int)isn describedBy:(char *)descript 
  1383. {
  1384.     char    *mybuffer;
  1385.     FIELD    *myField;
  1386.     int blkno;
  1387.     int    i,j, k, zero;
  1388.     fld_index *myFlds;
  1389.     
  1390.     if ((blkno = [self getBlockwithIsn:isn]) == -1)
  1391.         return NULL;
  1392.     
  1393.     myFlds = [self bldFldIndex:descript];
  1394.     zero = 0;
  1395.     i = 0;
  1396.     mybuffer = (char *)[self getBlk:blkno];
  1397.     j = locisn(isn,&mybuffer[0]);
  1398.     for (k = 0; k < myFlds->l; k++)    {
  1399.             myField = [self getFldDesc:k];
  1400.             if (myFlds->fld[k] != 0) 
  1401.             switch (myField->kind)    {
  1402.             case    'I':
  1403.                 gn_I_fld(&source[myFlds->ofset[k]],k,&mybuffer[j]);
  1404.                     break;
  1405.             case    'L':
  1406.                 gn_L_fld(&source[myFlds->ofset[k]],k,&mybuffer[j]);
  1407.                     break;
  1408.             case    'A':
  1409.                 gn_A_fld(&source[myFlds->ofset[k]],
  1410.                     k,myFlds->fld[k],&mybuffer[j]);
  1411.                     break;
  1412.             }
  1413.             
  1414.     }
  1415.     return self;
  1416. }
  1417.  
  1418. - (int)updateDataAtIsn:(int)isn with:(char *)data
  1419.     describedBy:(char *)description
  1420. {
  1421.     int i, j, k, space_used, blk_alloc, use_isn;
  1422.     char tmp_buffer[BUFFSIZE];
  1423.     
  1424.     if((j = [self getBlockwithIsn:(int)isn]) == -1) return -1;
  1425.     k = - [self delrec:j:isn:tmp_buffer];
  1426.     [self updBuf:j];
  1427.     space_used = [self allocSpace:k in:j];
  1428.     i = get_reclen(description) - k;
  1429.     if((blk_alloc = [self findSpace:i :(float)0.99]) == -1L)
  1430.     {
  1431.         [self getBlk:myInfo->data_file.blks];
  1432.         if((blk_alloc = [self findSpace:i :(float)0.99]) == -1L)
  1433.         {
  1434.         printf("Error: updateDataAtIsn...Unable to allocate new space\n");
  1435.             exit(0);
  1436.         }
  1437.     }
  1438.     use_isn = isn;
  1439.     j = [self updrec:blk_alloc:use_isn:data:description:tmp_buffer];
  1440.     [self setIsn:use_isn ToBlock:blk_alloc];
  1441.     [self updBuf:blk_alloc];
  1442.     space_used = [self allocSpace:j in:blk_alloc];
  1443.     return use_isn;
  1444. }
  1445.  
  1446. - (int)updrec:(int)blkno:(int)isn:(char *)source:(char *)
  1447.     descript:(char *)old_buffer
  1448. {
  1449.     char    *mybuffer;
  1450.     char    num_str[BUFFSIZE];
  1451.     FIELD    *myField;
  1452.     int    hold,i,j, k, zero;
  1453.     fld_index *myFlds;
  1454.  
  1455.     int nfields = [self numberFlds], mm;
  1456.     
  1457.     myFlds = [self bldFldIndex:descript];
  1458.     zero = 0;
  1459.  
  1460.     i = 0;
  1461.     mybuffer = (char *)[self getBlk:blkno];
  1462.         
  1463.     /* get place to put updated record */
  1464.     i = loc_eob(&mybuffer[0]);
  1465.     hold = i;
  1466.     put_num(&mybuffer[i+ISNRECSIZE],&isn);
  1467.     /* point past rec len and isn num    */
  1468.     i = i + ISNRECSIZE + ISNRECSIZE;
  1469.     /* reclen is stored in first ISNRECSIZE bytes */
  1470.     /* isn is stored in next ISNRECSIZE bytes    */
  1471.     j = i;
  1472.     for (k = 0; k < nfields; k++)    {
  1473.             myField = [self getFldDesc:k];
  1474.             if  (myFlds->fld[k] == 0)
  1475.                 if (( mm = loc_fld(k,&old_buffer[0])) != -1)    {
  1476.                         i = old_buffer[mm];
  1477.                         memcpy(&mybuffer[j],&old_buffer[mm],i);                
  1478.                         j = i+j;
  1479.                         }
  1480.                     else    {
  1481.                         i = pn_N_fld(&mybuffer[j]);
  1482.                         j=i+j;
  1483.                         }
  1484.         else    switch (myField->kind)    {
  1485.             case    'I':
  1486.                 i = pn_I_fld(&source[myFlds->ofset[k]],
  1487.                     &mybuffer[j]);
  1488.                 j=i+j;
  1489.                 if(myField->keyed == 'K')
  1490.                 {
  1491.                     if((gn_I_fld(num_str, k, &old_buffer[0])) != 0)
  1492.                     [self deleteKey:num_str isnNo:isn field:myField];
  1493.                     else [self deleteKey:"0" isnNo:isn field:myField];
  1494.                     if(gn_I_fld(num_str,k,&mybuffer[hold]) != 0)
  1495.                     [self addKey:num_str isnNo:isn field:myField];
  1496.                     else [self addKey:"0" isnNo:isn field:myField];
  1497.                 }
  1498.                     break;
  1499.             case    'L':
  1500.                 i = pn_L_fld(&source[myFlds->ofset[k]],
  1501.                     &mybuffer[j]);
  1502.                     j=i+j;
  1503.                 if(myField->keyed == 'K')
  1504.                 {
  1505.                     if((gn_L_fld(num_str, k, &old_buffer[0])) != 0)
  1506.                     [self deleteKey:num_str isnNo:isn field:myField];
  1507.                     else [self deleteKey:"0" isnNo:isn field:myField];
  1508.                     if(gn_L_fld(num_str,k,&mybuffer[hold]) != 0)
  1509.                     [self addKey:num_str isnNo:isn field:myField];
  1510.                     else [self addKey:"0" isnNo:isn field:myField];
  1511.                 }
  1512.                     break;
  1513.             case    'A':
  1514.             i = pn_A_fld(&source[myFlds->ofset[k]],
  1515.                 &mybuffer[j],myFlds->fld[k]);
  1516.                     j=i+j;
  1517.                 if(myField->keyed == 'K')
  1518.                 {
  1519.                     if((gn_A_fld(num_str, k, BUFFSIZE, &old_buffer[0])) != 0)
  1520.                     [self deleteKey:num_str isnNo:isn field:myField];
  1521.                     else [self deleteKey:"" isnNo:isn field:myField];
  1522.                     if(gn_A_fld(num_str,k,BUFFSIZE, &mybuffer[hold]) != 0)
  1523.                     [self addKey:num_str isnNo:isn field:myField];
  1524.                     else [self addKey:"" isnNo:isn field:myField];
  1525.                 }
  1526.                     break;
  1527.             }
  1528.             
  1529.     }
  1530.     /* store record len    */
  1531.     k = j - hold;
  1532.     put_num(&mybuffer[hold+0],&k);
  1533.     /* return record len    */
  1534.     return(k);
  1535. }
  1536.  
  1537.  
  1538. - deleteDataAtIsn:(int)isn
  1539. {
  1540.     int j, k, space_used;
  1541.     char tmp_buffer[BUFFSIZE];
  1542.     
  1543.     if((j = [self getBlockwithIsn:(int)isn]) == -1) return NULL;
  1544.     [self deKeyRecord:isn];
  1545.     k = - [self delrec:j:isn:tmp_buffer];
  1546.     [self setIsn:isn ToBlock:-1L];
  1547.     [self updBuf:j];
  1548.     space_used = [self allocSpace:k in:j];
  1549.     return self;
  1550. }
  1551.  
  1552. -(int)delrec:(int)block:(int)isn:(char *)tmp_buffer
  1553. {
  1554.     char *buff_ptr;
  1555.     int    i,j,k,isnlen, nxt_isn,len_of_remainder;
  1556. /*
  1557.     FIELD *myField;
  1558. */
  1559.     i = 0;
  1560.     j = 0;
  1561.     
  1562.     buff_ptr= (char *)[self getBlk:block];
  1563.     if ((j = locisn(isn,&buff_ptr[0]) ) == -1)
  1564.     {
  1565.         printf("Error: delrec...isn %d not located\n",isn);
  1566.     }
  1567.     isnlen = (int)get_num(&buff_ptr[j]);
  1568.     
  1569.     for (i=0;i<=isnlen;i++)
  1570.         tmp_buffer[i] = buff_ptr[j+i];
  1571.         
  1572.         /* points to next record or eob    */
  1573.         nxt_isn = j + isnlen;
  1574.         /* points to eob    */
  1575.         len_of_remainder = loc_eob(&buff_ptr[j]);
  1576.         
  1577.     k = nxt_isn;
  1578.     
  1579.     for(i=0;i<len_of_remainder;i++)
  1580.         buff_ptr[j++] = buff_ptr[k++];
  1581.     k = 0;
  1582.         
  1583.     put_num(&buff_ptr[j],&k);
  1584.             
  1585.     return(isnlen);
  1586. }
  1587.  
  1588. int
  1589. readRandom(p,fptr,blknum,blksize)
  1590.     int blksize;
  1591.     int blknum;
  1592.     char *p;
  1593.     FILE *fptr;
  1594. {
  1595.     long offset, curloc;
  1596.     
  1597.     if((curloc = ftell(fptr)) == -1L) {
  1598.     printf("Error: readRandom...ftell error at block %ld\n", blknum);
  1599.         exit(0);
  1600.         }
  1601.     offset = blknum * blksize - curloc;
  1602.     if(fseek(fptr, offset, 1) != 0)    {
  1603.     printf("Error: readRandom...fseek error at block %ld\n", blknum);
  1604.         exit(0);
  1605.         }
  1606.     fread(p, blksize, 1, fptr);
  1607.     if (ferror(fptr) != 0)    {
  1608.     printf("Error: readRandom...read error at block %ld\n", blknum);
  1609.         exit(0);
  1610.         }
  1611.     return(TRUE);        
  1612. }
  1613.  
  1614. int
  1615. writeRandom(p,fptr,blknum,blksize)
  1616.     int blksize;
  1617.     int blknum;
  1618.     char *p;
  1619.     FILE *fptr;
  1620. {
  1621.     long offset, curloc;
  1622.     
  1623.     if((curloc = ftell(fptr)) == -1L)    {
  1624.     printf("Error: writeRandom...ftell error at block %ld\n", blknum);
  1625.         exit(0);
  1626.         }
  1627.     offset = blknum * blksize - curloc;
  1628.     if(fseek(fptr, offset, 1) != 0)    {
  1629.     printf("Error: writeRandom...fseek error at block %ld\n", blknum);
  1630.         exit(0);
  1631.         }
  1632.     fwrite(p, blksize, 1, fptr);
  1633.     if (ferror(fptr) != 0)    {
  1634.     printf("Error: writeRandom...fwrite error at block %ld\n", blknum);
  1635.         exit(0);
  1636.         }
  1637.     return(TRUE);        
  1638. }
  1639.  
  1640. - (int)getBlockwithIsn:(int)isn
  1641. {
  1642.     int    k, block;
  1643.     int    j;
  1644.     int  *isns;
  1645.     
  1646.     if ( isn < 0 )
  1647.     {
  1648.         printf("Error: getisn...isn < 0\n");
  1649.         return(-1);
  1650.     }
  1651.     if (isn >= myInfo->last_isn )
  1652.     {
  1653.         printf("Error: getisn...isn > last_isn\n");
  1654.         return(-1);
  1655.     }
  1656.     
  1657.     j = isn/(NUM_ISNS);
  1658.     /* get offset into isn_block    */
  1659.     k = (isn - j * (NUM_ISNS));
  1660.         
  1661.     isns = [isnTable elementAt:j];
  1662.     block = isns[k];
  1663.     return(block- 1);        
  1664.     /* block is stored +1 to allow 0 to mean no block for that isn    */
  1665. }
  1666.  
  1667. - setIsn:(int)isn ToBlock:(int)block
  1668. {
  1669.     int    k;
  1670.     int    j;
  1671.     int  *isns;
  1672.     
  1673.     if ( isn < 0 )
  1674.     {
  1675.         printf("Error: setisn...isn < 0\n");
  1676.         exit(0);
  1677.     }
  1678.     if (isn > myInfo->max_isns )
  1679.     {
  1680.         printf("Error: setisn...isn > max_isns\n");
  1681.         exit(0);
  1682.     }
  1683.     
  1684.     j = isn/(NUM_ISNS);
  1685.     /* get offset into isn_block    */
  1686.     k = (isn - j * (NUM_ISNS));
  1687.         
  1688.     isns =[isnTable elementAt:j];
  1689.     /* block is stored +1 to allow 0 to mean no block for that isn    */
  1690.     isns[k] = block + 1;
  1691.     return self;        
  1692. }
  1693.  
  1694. - (int)geta_isn
  1695. {
  1696.     int    i;
  1697.     /* 0 is stored to mean empty.. getisn subs 1 to allow
  1698.         access to block 0 , i.e. block 0 is stored as 1
  1699.     */    
  1700.     for (i=0;i<myInfo->last_isn;i++)
  1701.         if ([self getBlockwithIsn:i] == -1) return(i);
  1702.     i = myInfo->last_isn;
  1703.     if (myInfo->last_isn == myInfo->max_isns)
  1704.         [self newIsnBlock];
  1705.     myInfo->last_isn++;
  1706.     return(i);
  1707. }
  1708.         
  1709. - newIsnBlock
  1710. {
  1711.     int *isns = (int *)calloc(NUM_ISNS,ISNSIZE);
  1712.     int *newisns = (int *)calloc(NUM_ISNS,ISNSIZE);
  1713.     int i,j,k, old_max;
  1714.     FIELD *myField;
  1715. /*
  1716.     KEY_VALUE *myKeys;
  1717.     int *key_isns;
  1718. */
  1719.     
  1720.     old_max = myInfo->max_isns;
  1721.     for (i=0; i< NUM_ISNS; i++)
  1722.         isns[i] = -1;
  1723.     
  1724. /*
  1725.     printf("***Adding isn Table element ***\n");
  1726. */
  1727.     [isnTable addElement:(int *)isns];
  1728.     myInfo->max_isns = myInfo->max_isns + NUM_ISNS;
  1729.  
  1730.     j = [self numberFlds];
  1731.     for (k=0;k<j;k++)
  1732.     {
  1733.         myField = [self getFldDesc:k];
  1734.     /* For each keyed field */
  1735.     if (myField->keyed == 'K')
  1736.         {
  1737.         /* Initializing new keyisn space */
  1738.             for (i=0; i< NUM_ISNS; i++)
  1739.                 newisns[i] = 0;
  1740.         /* Store new block */
  1741. /*
  1742.     printf("***Adding isn Table element for key %s***\n",myField->abbrev);
  1743. */
  1744.         [myField->key_isns addElement:(int *)newisns];
  1745.         }
  1746.     }
  1747.     free(isns);
  1748.     free(newisns);
  1749.     return self;
  1750. }
  1751.     
  1752. int
  1753. get_reclen(descript)
  1754.     char     descript[];
  1755. {
  1756.     int    i, j, k, fldlen;
  1757.     char fld_name[3];
  1758.     
  1759.     k = 0;
  1760.     i = 0;
  1761.     
  1762.     while(i < strlen(descript))    {
  1763.         j = get2(&descript[i],&fld_name,&fldlen);
  1764.         i = i + j;
  1765.         /* need room to store length    */
  1766.         k = k + fldlen+1;
  1767.         }
  1768.     /* room for isn, record len, and final byte    */
  1769.     return(k+ISNRECSIZE+ISNRECSIZE+1);
  1770. }
  1771.  
  1772. int
  1773. get2(descript,fld,fld_len)
  1774.     char    fld[], descript[];
  1775.     int  *fld_len;
  1776. {
  1777.     int m;
  1778.     long k;
  1779.  
  1780.     m = 0;
  1781.     while (descript[m] != '\0')    {
  1782.         fld[0] = descript[m++];
  1783.         fld[1] = descript[m++];
  1784.         fld[2] = '\0';
  1785.         m++;    /* skip past comma    */
  1786.         switch (descript[m])    {
  1787.             case 'I':
  1788.                 m++;
  1789.                 *fld_len = sizeof(m);
  1790.                 return(++m);
  1791.             case 'L':
  1792.                 m++;
  1793.                 *fld_len = sizeof(k);
  1794.                 return(++m);
  1795.             default:
  1796.                 *fld_len = (descript[m++] & 0x0f);
  1797.                 if ( descript[m] == '\0' ) break;
  1798.                 while (descript[m] != ',')
  1799.                 *fld_len = *fld_len * 10 + (descript[m++] & 0x0f);
  1800.                 return(++m);
  1801.             }
  1802.     }
  1803.     return(m);
  1804. }
  1805.  
  1806. - prtRecAtIsn:(int)isn
  1807. {
  1808.     int i, ii, j, k, blkno;
  1809.     int    nfields = [self numberFlds];
  1810.     long ll;
  1811.     char *mybuffer, prt_str[BUFFSIZE];
  1812.     FIELD *myField;
  1813.     
  1814.     i = 0;
  1815.     if ((blkno = [self getBlockwithIsn:isn]) == -1) return self;
  1816.     mybuffer = (char *)[self getBlk:blkno];
  1817.     j = locisn(isn,&mybuffer[0]);
  1818.     for (k = 0; k <  nfields; k++)
  1819.         {
  1820.             myField = [myDFD elementAt:k];    
  1821.             switch (myField->kind)    {
  1822.                 case    'I':
  1823.                     ii = 0;
  1824.                     gn_I_fld(&ii,k,&mybuffer[j]);
  1825.                     printf("%s : %d\n",myField->name,ii);
  1826.                     break;
  1827.                 case    'L':
  1828.                     ll = 0;
  1829.                     gn_L_fld(&ll,k,&mybuffer[j]);
  1830.                     printf("%s : %ld\n",myField->name,ll);
  1831.                     break;
  1832.                 case    'A':
  1833.                 strcpy(prt_str,"");
  1834.         gn_A_fld(prt_str,k,
  1835.             myField->display_len+1,&mybuffer[j]);
  1836.             printf("%s : %s\n",myField->name,prt_str);
  1837.                     break;
  1838.             }
  1839.             
  1840.         }
  1841.     return self;
  1842. }
  1843.  
  1844. - status
  1845. {
  1846.     int    i,k,isns_used;
  1847.     FIELD *myField;
  1848.     
  1849.     isns_used = 0;
  1850.     
  1851.     printf("------- Status Report for Data Base ---- %s ---\n",
  1852.         myInfo->dBaseName);
  1853.     for (i = 0;i<myInfo->last_isn;i++)
  1854.         if ( [self getBlockwithIsn:i] != -1) isns_used++;
  1855.         
  1856.     printf(" Created using version %d of software\n", myInfo->version);
  1857.     printf(" %d ISNs used out of a maximum of %d - next isn = %d\n",
  1858.         isns_used,myInfo->max_isns,myInfo->last_isn);
  1859.     printf(" %d Buffers allocated, size = %d\n",
  1860.         myInfo->nbuf, BUFFSIZE);
  1861.     printf(" %d isns stored per block\n",NUM_ISNS);
  1862.     printf(" Update space : %d percent\n",(int)((1.-myInfo->data_frac)*100));
  1863.     printf(" Last dump date and time were : %d %d\n"
  1864.         ,myInfo->dump_date,myInfo->dump_time);
  1865.     printf(" There are %d fields defined for the database\n"
  1866.         ,[self numberFlds]);
  1867.     printf(" There are %d keyed fields \n",
  1868.         [self numKeyedFlds]);
  1869.     printf("------- FILE USAGE--------------------------\n");
  1870.     printf("      FILE         ");
  1871.     for(i=0;i<8;i++)        printf("<%-5d",(i+1)*BUFFSIZE/8-1);
  1872.     printf(" TOTAL\n");
  1873.     printf("------------------------------------------------------------\n");
  1874.     [self prt_one_status];
  1875.     printf("------------------------------------------------------------\n");
  1876.     k = 0;
  1877.     for (i=0;i<[self numberFlds];i++)
  1878.     {
  1879.         myField = [self getFldDesc:i];
  1880.         if (myField->keyed == 'K')
  1881.             k = k + [myField->hash count] * sizeof(KEY_VALUE);
  1882.     }
  1883.     
  1884.     printf("Key value storage = %d bytes\n",
  1885.         k);
  1886.     printf("Isn storage = %d bytes\n",BUFFSIZE*[isnTable count]);
  1887.     printf("Key list storage = %d bytes\n",BUFFSIZE*[isnTable count]
  1888.         * [self numKeyedFlds]);
  1889.     printf("\n");
  1890.     return self;
  1891. }
  1892.     
  1893. - prt_one_status
  1894. {
  1895.         int    charno,i,j,k, comp_fact;
  1896.         int    block, old_block, use[8], total_avail;
  1897.         char *mybuffer;
  1898.         file_data *file_info = &(myInfo->data_file);
  1899.  
  1900.         comp_fact = BUFFSIZE/256;
  1901.         /*    amount of space represented by "1" in
  1902.             in block alloc table                    */
  1903.                                         
  1904.         old_block = -1;
  1905.         for (i = 0; i<8; i++)    use[i] = 0;
  1906.         total_avail = file_info->blks;
  1907.         
  1908.         for (k =0;k<file_info->blks;k++)    {
  1909.             charno = k;
  1910.             block = charno/BUFFSIZE;
  1911.             charno = mod(charno,BUFFSIZE);
  1912.             if ( block != old_block )
  1913.             {
  1914.                 mybuffer = [spaceTable elementAt:block];
  1915.                 old_block = block;
  1916.             }
  1917.         i = (mybuffer[charno] & 0XFF);
  1918.         i = i * comp_fact;
  1919.         /* space is divided by comp_fact in space avail list*/
  1920.         j =i /(BUFFSIZE/8);
  1921.         use[j] = use[j] + 1;
  1922.         }
  1923.         printf("%10.10s:      ",myInfo->dBaseName);
  1924.         for (i=0;i<8;i++)
  1925.             printf("%6d",use[i]);
  1926.         printf("%6d\n",total_avail);
  1927.         return self;
  1928. }
  1929.         
  1930. - prtStructure
  1931. {
  1932.         int i, j= [self numberFlds];
  1933.         FIELD *myField;
  1934.         
  1935. printf("--------- Record Structure  -----%s-------\n",myInfo->dBaseName);
  1936.     for(i=0;i<j;i++)    {
  1937.     myField = [myDFD elementAt:i];
  1938.     printf("%2d>%s:%c:%d \t%-16s %c %s\n",i,myField->abbrev,
  1939.             myField->kind,myField->display_len,
  1940.             myField->name,myField->keyed,
  1941.             myField->edit_mask);
  1942.         }
  1943.     printf("---------------------------------------------- \n");
  1944.  
  1945.     return self;
  1946. }
  1947.  
  1948. int
  1949. gn_I_fld(dptr,j,recordptr)
  1950.     int    j;
  1951.     char    dptr[],recordptr[];
  1952. {
  1953.     int i,k,l,field_len;
  1954.  
  1955.     if ((i = loc_fld(j,&recordptr[0])) == -1)
  1956.         field_len = 1;
  1957.         else    field_len = recordptr[i];
  1958.     if ((field_len-1) == 0)    {
  1959.             for (l = 0; l < sizeof(k); l++)
  1960.                  dptr[l] = '\0';
  1961.              return(0);
  1962.         }
  1963.         for (l = 0; l < sizeof(k); l++)
  1964.          dptr[l] = recordptr[l+i+1];
  1965.     return(1);
  1966. }
  1967.  
  1968. int
  1969. gn_L_fld(dptr,j,recordptr)
  1970.     int    j;
  1971.     char    dptr[],recordptr[];
  1972. {
  1973.     int i,l,field_len;
  1974.     long k;
  1975.     
  1976.     if ((i = loc_fld(j,&recordptr[0])) == -1)
  1977.         field_len = 1;
  1978.         else        field_len = recordptr[i];
  1979.     if ((field_len-1) == 0)    {
  1980.             for (l = 0; l < sizeof(k); l++)
  1981.                  dptr[l] = '\0';
  1982.              return(0);
  1983.         }
  1984.     for (l = 0; l < sizeof(k); l++)
  1985.          dptr[l] = recordptr[l+i+1];
  1986.     return(1);
  1987. }
  1988.  
  1989. int
  1990. gn_A_fld(dptr,j,lenreq,recordptr)
  1991.     int j,lenreq;
  1992.     char    dptr[],recordptr[];
  1993. {
  1994.     int    i,field_len,k;
  1995.  
  1996.     if ((i = loc_fld(j,&recordptr[0])) == -1)    
  1997.         field_len = 1;
  1998.         else    field_len = recordptr[i] - 1;
  1999.     if ((field_len - 1) == 0)    {
  2000.         strcpy(&dptr[0],"");
  2001.         return(0);
  2002.         }
  2003.     field_len= min(field_len,lenreq-1);
  2004.     /* be sure to leave room for terminating null */
  2005.         for (k=0; k<field_len; k++)    {
  2006.             dptr[k] = recordptr[i+k+1];
  2007.             dptr[k+1] = '\0';
  2008.     /* append null at end since not stored in record */
  2009.             }
  2010.     return(1);
  2011. }
  2012.  
  2013. - dumpSpace
  2014. {
  2015.     int i,j, k;
  2016.     char    *mySpace;
  2017.     
  2018.     j = [spaceTable count];
  2019.     printf("Dumping %d blocks of space table info\n",j);
  2020.     for (i=0; i<j; i++)
  2021.     {
  2022.         printf("Block %d ---------------\n",i);
  2023.         mySpace = (char *)[spaceTable elementAt:i];
  2024.         for (k=0; k<BUFFSIZE; k++)
  2025.         {
  2026.             if (mod (k,16) == 0)
  2027.                 printf("\n");
  2028.             printf("%02x",(mySpace[k] & 0xff));
  2029.         }
  2030.     printf("\n");
  2031.     }
  2032.     return self;
  2033. }
  2034.  
  2035. - dumpIsns
  2036. {
  2037.     int i,j, k;
  2038.     int    *myIsns;
  2039.     
  2040.     j = [isnTable count];
  2041.     printf("Dumping %d blocks of isn table info\n",j);
  2042.     for (i=0; i<j; i++)
  2043.     {
  2044.         printf("Block %d ---------------\n",i);
  2045.         myIsns = (int *)[isnTable elementAt:i];
  2046.         for (k=0; k<NUM_ISNS; k++)
  2047.         {
  2048.             if (mod (k,10) == 0)
  2049.                 printf("\n");
  2050.             printf("%5d ",*myIsns++);
  2051.         }
  2052.     printf("\n");
  2053.     }
  2054.     return self;
  2055. }
  2056.  
  2057. - dumpKeys
  2058. {
  2059.     return self;
  2060. }
  2061.  
  2062. int
  2063. loc_fld(i,buffer)
  2064.     int    i;
  2065.     char    buffer[];
  2066. {
  2067.     int field_ptr,k,field_len;
  2068.     
  2069.     /*    step past reclen and isn#    */
  2070.     field_ptr = ISNRECSIZE + ISNRECSIZE;    
  2071.     if (i == 0) return(field_ptr);
  2072.         for (k=1; k <= i; k++)    {
  2073.         field_len = buffer[field_ptr];
  2074.         if (field_len == '\0') return(-1);
  2075.         field_ptr = field_ptr + field_len;
  2076.         }
  2077.     if (buffer[field_ptr] == '\0') return(-1);
  2078.         else        return(field_ptr);
  2079. }
  2080.  
  2081. - dumpIsns:(int *)isns toFile:(char *)dump_file_name
  2082. {
  2083.     char    *mybuffer;
  2084.     char    a_out[256];
  2085.     int    i,j,k,l,len, i_out, l_out, isn;
  2086.     FILE    *dump_file;
  2087.     char str[3] = "|";
  2088.     FIELD *myField;
  2089.     
  2090.     dump_file = (FILE *)fopen(dump_file_name,"w");
  2091.     
  2092.     myInfo->dump_date = 0101;
  2093.     myInfo->dump_time = 151500;
  2094.  
  2095.     fprintf(dump_file,"%s%d%s%d\n",str,myInfo->dump_date,str,
  2096.         myInfo->dump_time,str);
  2097.  
  2098. /*
  2099.     if (myInfo->journal_flag)
  2100.         journal(dbname,tst_info->last_isn,DU,
  2101.             &buffer[0],tst_info->data_file.ptr);
  2102. */
  2103.     for (i=0;i<isns[0];i++)
  2104.         {
  2105.         isn = isns[i+1];
  2106.         if ((j = [self getBlockwithIsn:isn]) != -1 )    {
  2107.         mybuffer = (char *)[self getBlk:j];
  2108.         j = locisn(isn,&mybuffer[0]);
  2109.         fprintf(dump_file,"%s\n%d",str,isn);
  2110.     for (k = 0; k < [self numberFlds]; k++)
  2111.             {
  2112.                 myField = [self getFldDesc:k];
  2113.                 switch (myField->kind)    {
  2114.                 case    'I':
  2115.                         i_out = 0;
  2116.                     if ((l = gn_I_fld(&i_out,k,&mybuffer[j])) != 0)
  2117.                             fprintf(dump_file,"%s%d",str,i_out);
  2118.                         else
  2119.                             fprintf(dump_file,"%s",str);
  2120.                     break;
  2121.                 case    'L':
  2122.                         l_out = 0;
  2123.                     if ((l = gn_L_fld(&l_out,k,&mybuffer[j])) != 0)
  2124.                             fprintf(dump_file,"%s%ld",str,l_out);
  2125.                         else
  2126.                             fprintf(dump_file,"%s",str);
  2127.                     break;
  2128.                 case    'A':
  2129.                     len = 256;
  2130.                     strcpy(a_out,"");
  2131.                     if ((l = gn_A_fld(a_out,k,len,&mybuffer[j])) != 0)
  2132.                             fprintf(dump_file,"%s%s",str,a_out);
  2133.                         else
  2134.                             fprintf(dump_file,"%s",str);
  2135.                     break;
  2136.             }
  2137.         }    
  2138.     }
  2139.     }
  2140.     fprintf(dump_file,"\n");
  2141.     fclose(dump_file);
  2142.     
  2143. /*    Write completion of dump at date time to journal if required     */
  2144.     return self;
  2145. }
  2146.  
  2147.  
  2148. - loadDBfromFile:(char *)file_name
  2149. {
  2150.     FILE *fptr;
  2151.     char *desc_str = (char *)calloc(BUFFSIZE,sizeof(char));
  2152.     char *data_str = (char *)calloc(BUFFSIZE,sizeof(char));
  2153.     char delim;
  2154.     
  2155.     if(!(fptr = fopen(file_name,"r")))
  2156.     {
  2157.         printf("Error: loadDBFromFile...file %s not found\n",file_name);
  2158.         exit(0);
  2159.     }
  2160.     
  2161.     fgets(desc_str,128,fptr);    /* get dump dates */
  2162.     fgets(data_str,128,fptr);    /* get next line */
  2163.     delim = desc_str[0];
  2164.     
  2165.     while([self loadDB:fptr:desc_str:data_str:delim])
  2166.     {
  2167.         [self addData:data_str:desc_str];
  2168.     }    
  2169.     free(desc_str);
  2170.     free(data_str);
  2171.     return self;
  2172. }
  2173.  
  2174. - (int)loadDB:(FILE *)fptr:(char *)desc_str:(char *)data_str:(char)delim
  2175. {
  2176.     int i, ii, k;
  2177.     long ll;
  2178.     char *mybuffer, prt_str[1024], tmp_str[1024],
  2179.          *tmp, *hold_desc, *hold_data;
  2180.     FIELD *myField;
  2181.         
  2182.     hold_desc = desc_str;
  2183.     hold_data = data_str;
  2184.     strcpy(desc_str,"");
  2185.     strcpy(data_str,"");
  2186.     
  2187.     if(fgets(prt_str,1023,fptr) == NULL) return(FALSE);
  2188.     mybuffer = prt_str;
  2189.     while(*++mybuffer != delim);
  2190.     k = 0; 
  2191.     while(*mybuffer != '\0' && *mybuffer != '\n')    {
  2192.             if(*++mybuffer == delim || *mybuffer == '\n') {
  2193.                 if(++k >  [self numberFlds]) break;
  2194.                 continue;
  2195.             }
  2196.                 myField = [self getFldDesc:k];
  2197.                 *desc_str++ = myField->abbrev[0];
  2198.                 *desc_str++ = myField->abbrev[1];
  2199.                 *desc_str++ = ',';
  2200.                 tmp = tmp_str;
  2201.                 strcpy(tmp_str,"");
  2202.                 while(*mybuffer != delim && *mybuffer != '\0')
  2203.                     *tmp++ = *mybuffer++;
  2204.                 *tmp = '\0';
  2205.                 mybuffer--;
  2206.             switch (myField->kind)    {
  2207.                 case    'I':
  2208.                     *desc_str++ = 'I';
  2209.                     *desc_str++ = ',';
  2210.                     ii = atoi(tmp_str);
  2211.                     memcpy(data_str,&ii,sizeof(ii));
  2212.                     for(ii=0;ii<sizeof(ii);ii++)
  2213.                         data_str++;
  2214.                     break;
  2215.                 case    'L':
  2216.                     *desc_str++ = 'L';
  2217.                     *desc_str++ = ',';
  2218.                     ll = atol(tmp_str);
  2219.                     memcpy(data_str,&ll,sizeof(ll));
  2220.                     for(ii=0;ii<sizeof(ll);ii++)
  2221.                         data_str++;
  2222.                     break;
  2223.                 case    'A':
  2224.                     i = strlen(tmp_str) + 1;
  2225.                     if ( (i/100) > 0) *desc_str++ = (i/100) + 48;
  2226.                     if ((i-i/100)/10 > 0) *desc_str++ = mod(i,100)/10 + 48;
  2227.                     *desc_str++ = mod(i,10) + 48;
  2228.                     *desc_str++ = ',';
  2229.                     memcpy(data_str,tmp_str,i);
  2230.                     for(ii=0;ii<i;ii++)
  2231.                         data_str++;
  2232.                     break;
  2233.             }
  2234.         }
  2235.     *desc_str = '\0';
  2236.     *data_str = '\0';
  2237.     desc_str = hold_desc;
  2238.     data_str = hold_data;
  2239.     return(TRUE);
  2240. }
  2241.  
  2242. - (int *)andIsns
  2243. {
  2244. /* AND */
  2245.     int *last, *isns, *new;
  2246.     
  2247.     Isns = [self pushList:min(*Last,*Isns)];
  2248.     isns = Last;
  2249.     last = Hold;
  2250.     new = Isns;
  2251.     *new = 0;
  2252.     ++last;    ++isns; ++new;
  2253.     
  2254.     while(1)
  2255.         if ( *last < *isns )
  2256.            last++;
  2257.         else if ( *last > *isns )
  2258.                 isns++;
  2259.                 else    /* *last == *isns */
  2260.                 {
  2261.                         *new++ = *last++;  isns++; (*Isns)++;
  2262.                         if ( *(new-1) == LASTISN ) {
  2263.                     if(*Isns > 0) (*Isns)--;
  2264.                         else    new[1] = LASTISN;
  2265.                     return Isns;
  2266.                     }
  2267.                 }
  2268. }
  2269.  
  2270. - (int *)orIsns
  2271. {
  2272. /* OR */
  2273.     int *last, *isns, *new;
  2274.     
  2275.     Isns = [self pushList:*Last+*Isns];
  2276.     new = Isns;
  2277.     *new = 0;
  2278.     last = Hold;
  2279.     isns = Last;
  2280.     ++last;    ++isns; ++new;
  2281.     
  2282.     while(1)
  2283.         if ( *last < *isns )
  2284.            {
  2285.             *new++ = *last++;    (*Isns)++;
  2286.         }
  2287.         else if ( *last > *isns )
  2288.                 {
  2289.                     *new++ = *isns++; (*Isns)++;
  2290.                 }
  2291.                 else    /* *last == *isns */
  2292.                 {
  2293.                         *new++ = *last++;  isns++; (*Isns)++;
  2294.                         if ( *(new-1) == LASTISN ) {
  2295.                     (*Isns)--;
  2296.                     return Isns;
  2297.                     }
  2298.                 }
  2299. }
  2300.  
  2301. - (int *)xorIsns
  2302. {
  2303. /* XOR */
  2304.     int *last, *isns, *new;
  2305.     
  2306.     Isns = [self pushList:*Last+*Isns];
  2307.     new = Isns;
  2308.     *new = 0;
  2309.     last = Hold;
  2310.     isns = Last;
  2311.     ++last;    ++isns; ++new;
  2312.     
  2313.     while(1)
  2314.         if ( *last < *isns )
  2315.            {
  2316.             *new++ = *last++;    (*Isns)++;
  2317.         }
  2318.         else if ( *last > *isns )
  2319.                 {
  2320.                     *new++ = *isns++; (*Isns)++;
  2321.                 }
  2322.                 else    /* *last == *isns */
  2323.                 {
  2324.                         last++;  isns++;
  2325.                         if ( *(last-1) == LASTISN ) {
  2326.                     if(*Isns > 0) *new = LASTISN;
  2327.                         else    new[1] = LASTISN;
  2328.                     return Isns;
  2329.                     }
  2330.                 }
  2331. }
  2332.  
  2333. - (int *)notIsns
  2334. {
  2335.     /*    set Last = all and xor */
  2336.     [self getIsnListforField:"*" value:"ALL"];
  2337.     return [self xorIsns];
  2338. }
  2339.  
  2340. - (int *)getIsnList
  2341. {
  2342.     return Isns;
  2343. }
  2344.  
  2345. - (int *)getLastList
  2346. {
  2347.     return Last;
  2348. }
  2349.  
  2350. - (int)getListCount
  2351. {
  2352.     return *Isns;
  2353. }
  2354.  
  2355. int    max(i,j)
  2356.     int i,j;
  2357. {
  2358.     if ( i  >=  j) return (i);
  2359.     else return(j);
  2360. }
  2361.  
  2362. int mod(m,n)
  2363.     int    m,n;
  2364. {    
  2365.     
  2366.     if (n == 0)    {
  2367.         printf("Error: mod...modulus of 0 undefined\n");
  2368.         exit(0);
  2369.         }
  2370.     
  2371.     return( m - (m/n)*n );
  2372.     
  2373. }
  2374.  
  2375. int min(i,j)
  2376.     int    i,j;
  2377. {
  2378.     if ( i <= j ) return(i);
  2379.         else return(j);
  2380. }
  2381. @end
  2382.